﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading;
using System.Web;
using System.Web.Mvc;
using Kratos.Framework.ContentManagement.Models;
using Kratos.Framework.Infrastructures;
using Kratos.Framework.Modules.Core.Repositories;
using Kratos.Framework.Repositories;

namespace Kratos.Framework.Filters
{
    /// <summary>
    /// 权限拦截
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    public class KratosSecurityAttribute : KratosFilterAttribute
    {
        public KratosSecurityAttribute()
            : base(typeof(AuthenticateFilter))
        {
            Order = 0;
        }
    }

    public class AuthenticateFilter : IAuthorizationFilter
    {
        private readonly IRepository<UserInfo> _userRep;
        private readonly IFormsAuthentication _forms;
        private bool _isAuthenticated;

        public AuthenticateFilter(IRepository<UserInfo> userRep, IFormsAuthentication form)
        {
            _userRep = userRep;
            _forms = form;
        }

        protected virtual bool AuthorizeCore(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            bool ignoreAuthenticate = filterContext.ActionDescriptor.GetCustomAttributes(typeof(IgnoreAttribute), true).Length > 0;

            if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                return ignoreAuthenticate;
            }

            string controllerName = filterContext.RouteData.Values["controller"].ToString();
            string actionName = filterContext.RouteData.Values["action"].ToString();

            var user = _userRep.GetAll().GetUser(filterContext.HttpContext.User.Identity.Name);//获取当前用户信息
            if (user == null)
            {
                _forms.SignOut();
                return false;
            }

            Thread.CurrentPrincipal = filterContext.HttpContext.User = user;

            if (ignoreAuthenticate) return true;//忽略验证逻辑

            //获取所有被维护的Action权限
            IList<ActionPermission> actions = new List<ActionPermission>();
            //如果当前Action属于被维护的Action权限,没有被维护的不处理
            if (actions.Count(a => a.ControllerName == controllerName && a.ActionName == actionName) > 0)
            {
                //用户拥有的Action权限中是否包含当前的额Action
                if (user.ActionPermissions.Count(a => a.ControllerName == controllerName && a.ActionName == actionName) <= 0)
                    return false;
            }

            return true;
        }

        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            _isAuthenticated = AuthorizeCore(filterContext);
            if (_isAuthenticated)
            {
                HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
                cachePolicy.SetProxyMaxAge(new TimeSpan(0));
                cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
            }
            else
            {
                //修改成具体功能页面直接HandleUnauthorizedRequest，其他的就返回一个提示框（无权限）
                //filterContext.Result = new ContentResult { Content = @"alert('抱歉,你不具有当前操作的权限！')" };//功能权限弹出提示框
                HandleUnauthorizedRequest(filterContext);
            }
        }

        protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }

        private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
        {
            validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
        }

        protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }

            return _isAuthenticated ? HttpValidationStatus.Valid : HttpValidationStatus.IgnoreThisRequest;
        }
    }
}
